/*-------------------------------------------------------------------------
 *
 * strtof.c
 *
 * Portions Copyright (c) 2019-2022, PostgreSQL Global Development Group
 *
 *
 * IDENTIFICATION
 *	  src/port/strtof.c
 *
 *-------------------------------------------------------------------------
 */

#include "c.h"

#include <float.h>
#include <math.h>

#ifndef HAVE_STRTOF
/*
 * strtof() 是 C99 的一部分；这个版本仅仅是为了过时平台的利益。因此，它已知在边缘情况下返回不正确的值，这在任何此类平台的回归测试结果的变体文件中必须考虑。
 */

float strtof(const char *nptr, char **endptr)
{
	int			caller_errno = errno;
	double		dresult;
	float		fresult;

	errno = 0;
	dresult = strtod(nptr, endptr);
	fresult = (float) dresult;

	if (errno == 0)
	{
		/*
		 * 值可能对 double 而言是合适的，但对 float 却不是。
		 */
		if (dresult != 0 && fresult == 0)
			caller_errno = ERANGE;	/* 下溢 */
		if (!isinf(dresult) && isinf(fresult))
			caller_errno = ERANGE;	/* 上溢 */
	}
	else
		caller_errno = errno;

	errno = caller_errno;
	return fresult;
}

#elif HAVE_BUGGY_STRTOF
/*
 * 在 Windows 上，有一个稍微不同的问题：VS2013 有一个 strtof()
 * 能为有效输入返回正确结果，但可能未能报告下溢或上溢的错误，而是返回 0。通过在 strtof() 返回 0.0 或 [+-]Inf 时尝试 strtod() 来解决这个问题，如果结果不同则把它称为错误。此外，strtof() 对非规范输入的处理也不好，因此在这种情况下优先舍入 strtod() 的结果。（通常我们会说 “太糟糕了” 如果 strtof() 不支持非规范数，但既然我们已经在这里修复东西，那就尽可能做出最好的修复。）
 *
 * Cygwin 有一个 strtof()，实际上就是 (float)strtod()，这意味着我们无法避免双重舍入问题；但使用这个包装器确实让我们得到了适当的上/下溢检查。（此外，如果他们修复了自己的 strtof()，则包装器不会破坏任何东西。）
 *
 * 在 Mingw 上的测试结果表明它有同样的问题，尽管查看代码我无法搞清楚原因。
 */
float pg_strtof(const char *nptr, char **endptr)
{
	int			caller_errno = errno;
	float		fresult;

	errno = 0;
	fresult = (strtof) (nptr, endptr);
	if (errno)
	{
		/* 出错时，只需将错误返回给调用者。 */
		return fresult;
	}
	else if ((*endptr == nptr) || isnan(fresult) ||
			 ((fresult >= FLT_MIN || fresult <= -FLT_MIN) && !isinf(fresult)))
	{
		/*
		 * 如果我们没有得到可解析的内容，或者如果我们得到了非零的非规范
		 * 有限值（或 NaN）且没有错误，则将其返回给调用者而不产生错误。
		 */
		errno = caller_errno;
		return fresult;
	}
	else
	{
		/*
		 * 再试一次。这里 errno 已经是 0。
		 */
		double		dresult = strtod(nptr, NULL);

		if (errno)
		{
			/* 出错时，只需返回错误 */
			return fresult;
		}
		else if ((dresult == 0.0 && fresult == 0.0) ||
				 (isinf(dresult) && isinf(fresult) && (fresult == dresult)))
		{
			/* 两个值都是 0 或同符号的无穷大 */
			errno = caller_errno;
			return fresult;
		}
		else if ((dresult > 0 && dresult <= FLT_MIN && (float) dresult != 0.0) ||
				 (dresult < 0 && dresult >= -FLT_MIN && (float) dresult != 0.0))
		{
			/* 非规范但非零值 */
			errno = caller_errno;
			return (float) dresult;
		}
		else
		{
			errno = ERANGE;
			return fresult;
		}
	}
}

#endif
